package com.hex.ds.hdrs.engine.exec;

import com.hex.ds.hdrs.center.service.CenterManager;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.exception.BizException;
import com.hex.ds.hdrs.common.utils.HdrsDateUtil;
import com.hex.ds.hdrs.common.utils.ListUtil;
import com.hex.ds.hdrs.engine.manager.ToDoManager;
import com.hex.ds.hdrs.engine.manager.ToRunManager;
import com.hex.ds.hdrs.engine.service.ProcessorService;
import com.hex.ds.hdrs.label.service.ILabelJobService;
import com.hex.ds.hdrs.period.job.po.JobTask;
import com.hex.ds.hdrs.period.job.po.PeriodJob;
import com.hex.ds.hdrs.period.job.service.PeriodJobService;
import com.hex.ds.hdrs.period.task.po.PeriodTask;
import com.hex.ds.hdrs.period.task.util.TaskTrackHelper;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @Package: com.hex.ds.hdrs.engine.exec
 * @ClassName ProcessorExec
 * @Description: 处理器执行
 * @Author: jd.chen
 * @Date 2021/7/5 19:12
 * @Version v1.0
 **/
@Slf4j
public class ProcessorExec extends Thread {

    private volatile boolean stop = false;
    private volatile boolean run = true;
    private volatile boolean runningFlag = false;

    private ToDoManager toDoManager;
    private ToRunManager toRunManager;
    private ProcessorService processorService;
    private CenterManager centerManager;
    private ILabelJobService iLabelJobService;
    private PeriodJobService periodJobService;

    private String threadName;

    public ProcessorExec(ProcessorService processorService, String threadName) {
        this.processorService = processorService;
        this.toDoManager = processorService.getToDoManager();
        this.toRunManager = processorService.getToRunManager();
        this.centerManager = processorService.getCenterManager();
        this.iLabelJobService = processorService.getILabelJobService();
        this.periodJobService = processorService.getPeriodJobService();
        this.threadName = threadName;
    }

    /**
     * 获取线程名
     *
     * @return
     */
    public String getThreadName() {
        return threadName;
    }


    public boolean getRun() {
        return run;
    }

    public boolean getStop() {
        return stop;
    }

    /**
     * 线程正在处理任务标志
     *
     * @return
     */
    public boolean getRunningFlag() {
        return runningFlag;
    }

    /**
     * 线程暂停
     */
    public synchronized void stopThread() {
        // 如果stop已经为true，则当前线程等待
        while (stop) {
            try {
                wait();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                return;
            }
        }
        // 当stop为false时，才设置为true
        stop = true;
    }

    /**
     * 线程继续
     */
    public synchronized void continueThread() {
        if (stop) {
            stop = false;
            notifyAll();
        }
    }

    /**
     * 线程关闭
     */
    public void closeThread() {
        synchronized (this) {
            notifyAll();
        }
        run = false;
    }

    /**
     * 处理器执行
     */
    @Override
    public void run() {
        while (run) {
            PeriodTask task = null;
            try {
                if (this.isCanExec()) {
                    // 任务正在处理
                    runningFlag = true;
                    //从队列中获取任务
                    JobTask jobTask = processorService.getJobTaskFromQueue();
                    if (jobTask != null) {
                        String jobCode = jobTask.getJobCode();
                        log.debug("【ProcessorExec】处理器处理作业编码: {}, 业务日期: {}", jobCode, jobTask.getBizDate());
                        task = jobTask.getCurTask();
                        if (task == null) {
                            log.warn("【ProcessorExec】处理器处理作业, 作业编码: {}, 业务日期: {},没有获取到处理任务,并将该作业编码放回待处理队列中", jobCode, jobTask.getBizDate());
                            toDoManager.addJobToQueue(jobTask);
                        } else {
                            if (Const.TASK_STOP.equals(task.getTaskStatus())) {
                                log.warn("【ProcessorExec】处理器处理任务, 任务编码: {},业务日期: {},该任务处于暂停状态，不做处理", jobCode, jobTask.getBizDate());
                                toDoManager.addJobToQueue(jobTask);
                            } else {
                                //查询同一标签下的作业编码
                                List<String> jobCodes = iLabelJobService.queryLabelByJobCode(jobTask.getJobCode());
                                //相同标签下的作业是否都完成的标志
                                Boolean finishFlag = true;
                                if (!ListUtil.isEmpty(jobCodes)) {
                                    for (String code : jobCodes) {
                                        //查询作业实例 是否完成
                                        PeriodJob periodJob = periodJobService.queryByJobCodeAndBizDate(code, HdrsDateUtil.subDay(jobTask.getBizDate()));
                                        if (null != periodJob) {
                                            if (Const.JOB_TO_DO.equals(periodJob.getJobStatus())) {
                                                log.debug("【ProcessorExec】处理器处理任务, 同标签下的作业没有全部完成，作业编码: {},业务日期: {}", code, HdrsDateUtil.subDay(jobTask.getBizDate()));
                                                //有未完成的作业
                                                finishFlag = false;
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (!finishFlag) {
                                    TaskTrackHelper.addTaskTrack(task, TaskTrackHelper.execFail(Const.LABEL_FAIL));
                                    log.debug("【ProcessorExec】处理器处理任务, 同标签下的作业上个业务日期还没全完成，作业编码: {},业务日期: {}", jobCode, jobTask.getBizDate());
                                    toDoManager.addJobToQueue(jobTask);
                                } else {
                                    this.processorExec(jobTask, task);
                                }
                            }
                        }
                    } else {
                        log.debug("【ProcessorExec】待处理队列中没有任务任何任务了");
                        Thread.sleep(50);
                    }
                } else {
                    log.debug("【ProcessorExec.stop】: {},【centerManager.isCanDeal()】:【{}】", stop, centerManager.isCanDeal());
                    Thread.sleep(100);
                }
            } catch (Exception e) {
                log.error("【ProcessorExec.run】处理器获取任务异常: {}",e.getMessage(), e);
                toRunManager.taskDealFail(task, e.getMessage());
            } finally {
                log.debug("【ProcessorExec.run】处理任务结束，线程线程号【{}】《=======", this.threadName);
                runningFlag = false;
                toDoManager.threadSleep();
            }
        }
        log.error("线程跳出【ProcessorExec.run】【{}】", threadName);
    }

    /**
     * 是否可执行
     *
     * @return
     */
    public boolean isCanExec() {
        if (!centerManager.isCanDeal()) {
            log.debug("【ProcessorExec.isCanExec】该中心不是Master======");
            return false;
        }
        if (stop) {
            log.debug("【ProcessorExec.isCanExec】处理器暂停======");
            return false;
        }
        return true;
    }

    /**
     * 判断依赖
     *
     * @param jobTask
     */
    public void processorExec(JobTask jobTask, PeriodTask curTask) {
        String jobBizDate = jobTask.getBizDate();
        String taskBizDate = curTask.getBizDate();
        String taskCode = curTask.getTaskCode();
        try {
            if (!jobBizDate.equals(taskBizDate)) {
                log.error("【ProcessorExec】处理器处理任务,任务编码: {},业务日期: {},与作业的业务日期: {}不相等", taskCode, taskBizDate, jobBizDate);
                toDoManager.removeJob(jobTask);
                return;
            }
            log.debug("【0】判断是否到达执行时间 -- 开始");
            this.processorService.checkRunTime(curTask);
            log.debug("【0】判断是否到达执行时间 -- 结束");

            log.debug("【1】是否存在互斥任务/作业执行中--开始");
            this.processorService.checkMutex(curTask);
            log.debug("【1】是否存在互斥任务/作业执行中--结束");

            log.debug("【2】检查上游依赖--开始");
            this.processorService.checkUpDepend(curTask);
            log.debug("【2】检查上游依赖--结束");

            log.debug("【3】所有上游依赖已完成，作业加入到待执行队列--开始");
            this.toDoManager.toDoToToRun(jobTask, curTask, Const.TRACK_TYPE_DO_TO_RUN, toRunManager);
            log.debug("【3】所有上游依赖已完成，作业加入到待执行队列--结束");
        } catch (BizException e) {
            log.debug("【任务编码: {}】【业务日期: {}】【processorExec】biz异常：{}",taskCode, taskBizDate, e.getErrMsg(), e);
            toRunManager.taskDealFail(curTask, e.getErrMsg());
            toDoManager.addJobToQueue(jobTask);
        } catch (Exception e) {
            log.error("【任务编码: {}】【业务日期: {}】【processorExec】异常：{}", taskCode, taskBizDate, e.getMessage(), e);
            toRunManager.taskDealFail(curTask, e.getMessage());
            toDoManager.addJobToQueue(jobTask);
        } finally {
            log.debug("【4】作业【{}】【{}】、任务【{}】【{}】依赖判断结束《===", curTask.getJobCode(),
                    jobBizDate, curTask.getTaskCode(), taskBizDate);
        }
    }

}
